﻿
package extremefx.storage {
	import extremefx.events.EventHandler;
	import extremefx.events.ObjectEventArgs;
	import extremefx.events.StatusEventArgs;
	
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.NetStatusEvent;
	import flash.events.ProgressEvent;
	import flash.net.NetConnection;
	import flash.net.NetStream;	

	/**
	 * @author Marcelo Volmaro
	 */
	public class VideoLoader extends QeuedItem {
		private var _stream:NetStream;
		private var _checkVideo:Sprite;
		private var _netconn:NetConnection;
		private var _metadata:Object;
		private var _video:NetStream;

		public function VideoLoader(pUrl:*) {
			super(pUrl, null);
			_video = null;
		}

		override public function start():Boolean {
			var r:Boolean = super.start();
			if (r){
				var nc:NetConnection = _netconn = new NetConnection();
				var stream:NetStream = _stream = new NetStream(nc);
				_addHandlers(stream);
				stream.addEventListener(NetStatusEvent.NET_STATUS, _onNetStatus, false, 0, true);
            	stream.addEventListener(IOErrorEvent.IO_ERROR, _onIOError, false, 0, true);
            	stream.client = {
            		onPlayStatus:_onPlayStatus,
            		onMetaData:_onMetaData,
            		onCuePoint:_onCuePoint
            	};
            	
            	_checkVideo = new Sprite();
            	_checkVideo.addEventListener(Event.ENTER_FRAME, _checkVideoSize, false, 0, true);
            	
                stream.play(_loadUrl);
                stream.seek(0);
			}
			
			return r;
		}
		
		override public function stop():Boolean {
			var r:Boolean = super.stop();
			if (r){
				try{
					_stream.close();
				} catch(error:Error){}
			}
			
			return r;
		}
		
		public function get video():NetStream { 
			return _video; 
		}
		
		override public function dispose():void {
			super.dispose();
			if (_stream){
				_stream.removeEventListener(NetStatusEvent.NET_STATUS, _onNetStatus);
            	_stream.removeEventListener(IOErrorEvent.IO_ERROR, _onIOError);
			}
			
			_stream = null;
			_netconn = null;
		}
		
		override protected function _removeHandlers():void{
			super._removeHandlers();
			if (_checkVideo) {
				_checkVideo.removeEventListener(Event.ENTER_FRAME, _checkVideoSize);
				_checkVideo = null;
			}
		}
		
		private function _checkVideoSize():void{
        	if(_bytesTotal == _bytesLoaded && _bytesTotal > 8){
                _checkVideo.removeEventListener(Event.ENTER_FRAME, _checkVideoSize, false);
                _onComplete(new Event(Event.COMPLETE));
                
            }else if(_bytesTotal == 0 && _stream.bytesTotal > 4){
                _onOpen(new Event(Event.OPEN));
                _bytesLoaded = _stream.bytesLoaded;
                _bytesTotal = _stream.bytesTotal;
                
            }else{
                var event:ProgressEvent = new ProgressEvent(ProgressEvent.PROGRESS, false, false, _stream.bytesLoaded, _stream.bytesTotal);
                _onProgress(event);
            }
        }
        
        //for Video
        private function _onPlayStatus(pE:Object):void{
        	if (_eOnPlayStatus) _eOnPlayStatus.fire(new StatusEventArgs(pE.info.code, pE.info.level));
        }
		
        private function _onMetaData(pMetadata:Object):void{
        	_metadata = pMetadata;
        	if (_eOnMetaData) _eOnMetaData.fire(new ObjectEventArgs(pMetadata));
        }
		
        private function _onCuePoint(pCuePoint:Object):void{
        	if (_eOnCuePoint) _eOnCuePoint.fire(new ObjectEventArgs(pCuePoint));
        }
        
        private function _onNetStatus(pE:NetStatusEvent):void {
			_stream.removeEventListener(NetStatusEvent.NET_STATUS, _onNetStatus, false);
            if(pE.info.code == "NetStream.Play.Start"){
                _video = _stream;
                if (_eOnNetStatus) _eOnNetStatus.fire(new StatusEventArgs(pE.info.code, pE.info.level));
			}
		}
		
		private var _eOnNetStatus:EventHandler;
		/**
		 * Event. Fires on Net Status changes.
		 */
		public function get onNetStatus():EventHandler{
			if (_eOnNetStatus == null) _eOnNetStatus = new EventHandler(this);
			return _eOnNetStatus;
		}
		
		private var _eOnMetaData:EventHandler;
		/**
		 * Event. Fires every time the class receives some Metadata information
		 */
		public function get onMetaData():EventHandler{
			if (_eOnMetaData == null) _eOnMetaData = new EventHandler(this);
			return _eOnMetaData;
		}
		
		private var _eOnCuePoint:EventHandler;
		/**
		 * Event. Fires on every cuepoint on a video.
		 */
		public function get onCuePoint():EventHandler{
			if (_eOnCuePoint == null) _eOnCuePoint = new EventHandler(this);
			return _eOnCuePoint;
		}
		
		private var _eOnPlayStatus:EventHandler;
		/**
		 * Event. Fires every time the play status changes.
		 */
		public function get onPlayStatus():EventHandler{
			if (_eOnPlayStatus == null) _eOnPlayStatus = new EventHandler(this);
			return _eOnPlayStatus;
		}
	}
}
